import os
import re
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
from pathlib import Path
import json
from collections import defaultdict

class MarkdownAttributeEditor:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("Markdown属性编辑器")
        self.root.geometry("900x700")
        
        self.directory = None
        self.reference_directory = None  # 单独的参考目录
        self.md_files = []
        self.current_file_index = 0
        self.attribute_entries = {}
        self.attribute_references = defaultdict(set)  # 存储所有文件的属性值作为参考
        
        # 定义属性字段
        self.attributes = [
            "tags", "type", "actor_id", "name", "aliases", 
            "link", "罩杯", "风格", "气质", "体型", "演技"
        ]
        
        # 创建界面
        self.create_widgets()
    
    def create_widgets(self):
        # 顶部按钮框架
        button_frame = tk.Frame(self.root)
        button_frame.pack(pady=10)
        
        tk.Button(button_frame, text="选择编辑目录", command=self.select_edit_directory).pack(side=tk.LEFT, padx=5)
        tk.Button(button_frame, text="选择参考目录", command=self.select_reference_directory).pack(side=tk.LEFT, padx=5)
        tk.Button(button_frame, text="加载参考值", command=self.load_reference_values).pack(side=tk.LEFT, padx=5)
        tk.Button(button_frame, text="保存当前文件", command=self.save_current_file).pack(side=tk.LEFT, padx=5)
        tk.Button(button_frame, text="批量保存所有文件", command=self.batch_save).pack(side=tk.LEFT, padx=5)
        
        # 目录状态显示
        status_frame = tk.Frame(self.root)
        status_frame.pack(pady=5)
        
        self.edit_dir_label = tk.Label(status_frame, text="编辑目录: 未选择", fg="blue")
        self.edit_dir_label.pack(anchor="w")
        
        self.ref_dir_label = tk.Label(status_frame, text="参考目录: 未选择", fg="green")
        self.ref_dir_label.pack(anchor="w")
        
        self.ref_status_label = tk.Label(status_frame, text="参考值: 未加载", fg="red")
        self.ref_status_label.pack(anchor="w")
        
        # 文件导航框架
        nav_frame = tk.Frame(self.root)
        nav_frame.pack(pady=5)
        
        self.file_label = tk.Label(nav_frame, text="未选择编辑目录")
        self.file_label.pack(side=tk.LEFT, padx=5)
        
        tk.Button(nav_frame, text="上一个", command=self.previous_file).pack(side=tk.LEFT, padx=5)
        tk.Button(nav_frame, text="下一个", command=self.next_file).pack(side=tk.LEFT, padx=5)
        
        # 属性编辑框架
        edit_frame = tk.Frame(self.root)
        edit_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 创建滚动框架
        canvas = tk.Canvas(edit_frame)
        scrollbar = ttk.Scrollbar(edit_frame, orient="vertical", command=canvas.yview)
        self.scrollable_frame = ttk.Frame(canvas)
        
        self.scrollable_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
        )
        
        canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
        canvas.configure(yscrollcommand=scrollbar.set)
        
        canvas.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")
        
        # 创建属性输入字段
        self.create_attribute_fields()
    
    def create_attribute_fields(self):
        # 清空现有字段
        for widget in self.scrollable_frame.winfo_children():
            widget.destroy()
        
        # 创建属性输入字段
        for i, attr in enumerate(self.attributes):
            # 标签
            label = tk.Label(self.scrollable_frame, text=f"{attr}:")
            label.grid(row=i, column=0, sticky="w", padx=5, pady=5)
            
            # 输入框
            if attr in ["tags", "风格", "气质", "体型", "演技"]:
                # 多行文本框用于数组类型的属性
                entry = tk.Text(self.scrollable_frame, height=3, width=50)
                self.attribute_entries[attr] = entry
                entry.grid(row=i, column=1, padx=5, pady=5, sticky="ew")
            else:
                # 单行文本框用于简单属性
                entry = tk.Entry(self.scrollable_frame, width=50)
                self.attribute_entries[attr] = entry
                entry.grid(row=i, column=1, padx=5, pady=5, sticky="ew")
            
            # 参考按钮
            ref_button = tk.Button(
                self.scrollable_frame, 
                text="参考", 
                command=lambda a=attr: self.show_attribute_reference(a),
                width=6,
                state="disabled"  # 初始状态为禁用
            )
            ref_button.grid(row=i, column=2, padx=5, pady=5)
            
            # 保存按钮引用，便于后续启用/禁用
            self.attribute_entries[attr + "_button"] = ref_button
    
    def update_reference_buttons_state(self):
        """更新参考按钮的状态"""
        has_references = any(len(values) > 0 for values in self.attribute_references.values())
        
        for attr in self.attributes:
            button = self.attribute_entries.get(attr + "_button")
            if button:
                if has_references:
                    button.config(state="normal")
                else:
                    button.config(state="disabled")
    
    def select_edit_directory(self):
        """选择要编辑的目录"""
        self.directory = filedialog.askdirectory(title="选择要编辑的Markdown文件目录")
        if self.directory:
            self.edit_dir_label.config(text=f"编辑目录: {os.path.basename(self.directory)}")
            self.load_edit_files()
            if self.md_files:
                self.current_file_index = 0
                self.load_file_attributes()
            else:
                messagebox.showinfo("提示", "编辑目录中没有找到Markdown文件")
    
    def select_reference_directory(self):
        """选择参考目录"""
        self.reference_directory = filedialog.askdirectory(title="选择参考目录（用于加载属性值）")
        if self.reference_directory:
            self.ref_dir_label.config(text=f"参考目录: {os.path.basename(self.reference_directory)}")
    
    def load_reference_values(self):
        """从参考目录加载属性值"""
        if not self.reference_directory:
            messagebox.showwarning("警告", "请先选择参考目录")
            return
        
        # 收集参考目录中的属性值
        self.collect_attribute_references()
        
        # 更新参考按钮状态
        self.update_reference_buttons_state()
        
        # 显示统计信息
        ref_count = sum(len(values) for values in self.attribute_references.values())
        loaded_count = sum(1 for values in self.attribute_references.values() if len(values) > 0)
        
        self.ref_status_label.config(
            text=f"参考值: 已加载 {ref_count} 个值 ({loaded_count}/{len(self.attributes)} 个属性)",
            fg="green"
        )
        
        messagebox.showinfo("参考值已加载", 
                          f"已从参考目录中收集到 {ref_count} 个属性参考值\n"
                          f"涉及 {loaded_count} 个不同的属性")
    
    def show_attribute_reference(self, attribute):
        """显示属性参考值"""
        if not self.attribute_references[attribute]:
            messagebox.showinfo("参考", f"属性 '{attribute}' 没有可用的参考值")
            return
        
        # 创建参考窗口
        ref_window = tk.Toplevel(self.root)
        ref_window.title(f"{attribute} 参考值 (共{len(self.attribute_references[attribute])}个)")
        ref_window.geometry("500x400")
        
        # 添加搜索框
        search_frame = tk.Frame(ref_window)
        search_frame.pack(fill=tk.X, padx=10, pady=5)
        
        search_label = tk.Label(search_frame, text="搜索:")
        search_label.pack(side=tk.LEFT)
        
        search_var = tk.StringVar()
        search_entry = tk.Entry(search_frame, textvariable=search_var, width=30)
        search_entry.pack(side=tk.LEFT, padx=5)
        search_entry.focus()
        
        # 添加列表框
        list_frame = tk.Frame(ref_window)
        list_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
        
        listbox = tk.Listbox(list_frame, font=("Arial", 10))
        listbox.pack(fill=tk.BOTH, expand=True)
        
        # 添加滚动条
        scrollbar = ttk.Scrollbar(listbox, orient=tk.VERTICAL, command=listbox.yview)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        listbox.config(yscrollcommand=scrollbar.set)
        
        # 填充参考值
        self.populate_reference_list(listbox, attribute)
        
        # 添加底部按钮
        button_frame = tk.Frame(ref_window)
        button_frame.pack(fill=tk.X, padx=10, pady=5)
        
        tk.Button(
            button_frame, 
            text="插入选中值", 
            command=lambda: self.insert_reference_value(attribute, listbox)
        ).pack(side=tk.LEFT, padx=5)
        
        tk.Button(
            button_frame, 
            text="添加到当前值", 
            command=lambda: self.append_reference_value(attribute, listbox)
        ).pack(side=tk.LEFT, padx=5)
        
        tk.Button(
            button_frame, 
            text="关闭", 
            command=ref_window.destroy
        ).pack(side=tk.RIGHT, padx=5)
        
        # 搜索功能
        def update_list(*args):
            search_term = search_var.get().lower()
            listbox.delete(0, tk.END)
            
            for value in sorted(self.attribute_references[attribute]):
                if search_term in value.lower():
                    listbox.insert(tk.END, value)
        
        search_var.trace("w", update_list)
        
        # 双击插入值
        listbox.bind("<Double-Button-1>", lambda e: self.insert_reference_value(attribute, listbox))
    
    def populate_reference_list(self, listbox, attribute):
        """填充参考值到列表框"""
        # 清空列表框
        listbox.delete(0, tk.END)
        
        # 添加排序后的参考值
        for value in sorted(self.attribute_references[attribute]):
            listbox.insert(tk.END, value)
    
    def insert_reference_value(self, attribute, listbox):
        """将选中的参考值插入到属性输入框中（替换当前内容）"""
        selection = listbox.curselection()
        if not selection:
            messagebox.showwarning("警告", "请先选择一个值")
            return
        
        value = listbox.get(selection[0])
        entry = self.attribute_entries[attribute]
        
        if isinstance(entry, tk.Text):
            # 多行文本框 - 替换所有内容
            entry.delete(1.0, tk.END)
            entry.insert(1.0, value)
        else:
            # 单行文本框 - 替换内容
            entry.delete(0, tk.END)
            entry.insert(0, value)
    
    def append_reference_value(self, attribute, listbox):
        """将选中的参考值添加到属性输入框中（追加内容）"""
        selection = listbox.curselection()
        if not selection:
            messagebox.showwarning("警告", "请先选择一个值")
            return
        
        value = listbox.get(selection[0])
        entry = self.attribute_entries[attribute]
        
        if isinstance(entry, tk.Text):
            # 多行文本框 - 添加到新行
            current_content = entry.get(1.0, tk.END).strip()
            if current_content:
                new_content = current_content + "\n" + value
            else:
                new_content = value
            
            entry.delete(1.0, tk.END)
            entry.insert(1.0, new_content)
        else:
            # 单行文本框 - 添加到末尾（用逗号分隔）
            current_content = entry.get().strip()
            if current_content:
                new_content = current_content + ", " + value
            else:
                new_content = value
            
            entry.delete(0, tk.END)
            entry.insert(0, new_content)
    
    def collect_attribute_references(self):
        """从参考目录收集所有文件的属性值作为参考"""
        # 清空现有参考值
        for attr in self.attributes:
            self.attribute_references[attr].clear()
        
        # 查找参考目录中的Markdown文件
        reference_files = []
        for file_path in Path(self.reference_directory).rglob("*.md"):
            reference_files.append(file_path)
        
        if not reference_files:
            messagebox.showwarning("警告", "参考目录中没有找到Markdown文件")
            return
        
        # 遍历所有参考文件收集属性值
        ref_file_count = 0
        for file_path in reference_files:
            try:
                with open(file_path, 'r', encoding='utf-8') as f:
                    content = f.read()
                
                front_matter = self.parse_front_matter(content)
                ref_file_count += 1
                
                for attr in self.attributes:
                    if attr in front_matter:
                        value = front_matter[attr]
                        if isinstance(value, list):
                            # 数组属性 - 添加所有元素
                            for item in value:
                                if item and str(item).strip():  # 跳过空值
                                    self.attribute_references[attr].add(str(item).strip())
                        else:
                            # 简单属性 - 添加值
                            if value and str(value).strip():  # 跳过空值
                                self.attribute_references[attr].add(str(value).strip())
            except Exception as e:
                print(f"读取参考文件失败 {file_path}: {e}")
        
        print(f"从 {ref_file_count} 个参考文件中收集到属性值")
    
    def load_edit_files(self):
        """加载编辑目录中的文件"""
        self.md_files = []
        for file_path in Path(self.directory).rglob("*.md"):
            self.md_files.append(file_path)
        
        self.file_label.config(text=f"文件: 1/{len(self.md_files)}")
    
    def load_file_attributes(self):
        """加载当前文件的属性到编辑框"""
        if not self.md_files:
            return
        
        file_path = self.md_files[self.current_file_index]
        self.file_label.config(text=f"文件: {self.current_file_index + 1}/{len(self.md_files)} - {file_path.name}")
        
        # 读取文件内容
        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()
        
        # 解析front matter
        front_matter = self.parse_front_matter(content)
        
        # 填充属性值到输入框
        for attr in self.attributes:
            entry = self.attribute_entries[attr]
            
            # 清空当前内容
            if isinstance(entry, tk.Text):
                entry.delete(1.0, tk.END)
            else:
                entry.delete(0, tk.END)
            
            # 设置新值
            if attr in front_matter:
                value = front_matter[attr]
                if isinstance(value, list):
                    # 数组类型属性，每行一个元素
                    if isinstance(entry, tk.Text):
                        entry.insert(1.0, "\n".join(value))
                    else:
                        entry.insert(0, ", ".join(value))
                else:
                    # 简单属性
                    if isinstance(entry, tk.Text):
                        entry.insert(1.0, str(value))
                    else:
                        entry.insert(0, str(value))
    
    def parse_front_matter(self, content):
        """解析Markdown文件的front matter"""
        front_matter = {}
        
        # 匹配front matter（两个---之间的内容）
        match = re.search(r'^---\s*\n(.*?)\n---', content, re.DOTALL)
        if match:
            front_matter_text = match.group(1)
            
            # 解析YAML格式的front matter
            lines = front_matter_text.split('\n')
            current_key = None
            current_list = []
            
            for line in lines:
                line = line.strip()
                if not line:
                    continue
                
                # 处理键值对
                if ':' in line and not line.startswith(' '):
                    # 保存上一个列表（如果有）
                    if current_key and current_list:
                        front_matter[current_key] = current_list
                        current_list = []
                    
                    key, value = line.split(':', 1)
                    key = key.strip()
                    value = value.strip()
                    
                    if value.startswith('[') and value.endswith(']'):
                        # 数组格式
                        try:
                            # 尝试解析JSON数组
                            front_matter[key] = json.loads(value)
                        except:
                            # 简单分割
                            items = value[1:-1].split(',')
                            front_matter[key] = [item.strip() for item in items if item.strip()]
                    elif value.startswith('-'):
                        # YAML列表格式
                        current_key = key
                        current_list = [value[1:].strip()]
                    elif value:
                        # 简单值
                        front_matter[key] = value
                    else:
                        # 空值，可能是列表的开始
                        current_key = key
                        current_list = []
                elif line.startswith('- ') and current_key:
                    # 列表项
                    current_list.append(line[2:].strip())
                elif current_key and current_list:
                    # 续行（简化处理）
                    pass
            
            # 保存最后一个列表（如果有）
            if current_key and current_list:
                front_matter[current_key] = current_list
        
        return front_matter
    
    def save_current_file(self):
        if not self.md_files:
            return
        
        file_path = self.md_files[self.current_file_index]
        self.save_file_attributes(file_path)
        messagebox.showinfo("成功", f"已保存: {file_path.name}")
    
    def batch_save(self):
        if not self.md_files:
            return
        
        result = messagebox.askyesno("确认", f"确定要批量修改 {len(self.md_files)} 个文件吗？")
        if result:
            for file_path in self.md_files:
                self.save_file_attributes(file_path)
            messagebox.showinfo("成功", f"已批量保存 {len(self.md_files)} 个文件")
    
    def save_file_attributes(self, file_path):
        # 读取文件内容
        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()
        
        # 解析现有的front matter
        front_matter_match = re.search(r'^---\s*\n(.*?)\n---', content, re.DOTALL)
        
        if front_matter_match:
            # 替换现有的front matter
            old_front_matter = front_matter_match.group(0)
            new_front_matter = self.generate_front_matter()
            
            content = content.replace(old_front_matter, new_front_matter)
        else:
            # 添加新的front matter
            new_front_matter = self.generate_front_matter()
            content = new_front_matter + '\n' + content
        
        # 写回文件
        with open(file_path, 'w', encoding='utf-8') as f:
            f.write(content)
    
    def generate_front_matter(self):
        """根据输入框的值生成front matter"""
        front_matter_lines = ["---"]
        
        for attr in self.attributes:
            entry = self.attribute_entries[attr]
            
            if isinstance(entry, tk.Text):
                value = entry.get(1.0, tk.END).strip()
            else:
                value = entry.get().strip()
            
            if value:
                # 处理数组类型的属性
                if attr in ["tags", "风格", "气质", "体型", "演技"]:
                    # 按行分割，过滤空行
                    items = [line.strip() for line in value.split('\n') if line.strip()]
                    if items:
                        front_matter_lines.append(f"{attr}:")
                        for item in items:
                            front_matter_lines.append(f"  - {item}")
                else:
                    front_matter_lines.append(f"{attr}: {value}")
        
        front_matter_lines.append("---")
        return "\n".join(front_matter_lines)
    
    def previous_file(self):
        if self.md_files and self.current_file_index > 0:
            self.current_file_index -= 1
            self.load_file_attributes()
    
    def next_file(self):
        if self.md_files and self.current_file_index < len(self.md_files) - 1:
            self.current_file_index += 1
            self.load_file_attributes()
    
    def run(self):
        self.root.mainloop()

if __name__ == "__main__":
    editor = MarkdownAttributeEditor()
    editor.run()